home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
vol6n14.arc
/
DR.ASM
next >
Wrap
Assembly Source File
|
1987-05-14
|
65KB
|
1,412 lines
; DR.asm
; Format: DR [d:][directory][/E][/S][/D][/T][/O]
CODE SEGMENT ;*************************;
ASSUME CS:CODE,DS:CODE ;* *;
ORG 100H ;* REMEMBER TO EXE2BIN *;
;* *;
START: JMP BEGINNING ;*************************;
; DATA AREA
; ---------
; DB 'Copyright 1987 Ziff-Davis Publishing Co.'
; DB 'Michael J. Mefford'
CURRENT_DISK DB ?
STATUS_REG DW ?
VIDEO_SEG DW 0B000H
NORMAL DB 07H
INVERSE DB 70H
BAR_ATTRIBUTE DB 70H
CURSOR_TYPE DW ?
SORT_OFFSET DW 0
SORT_TABLE DW 0,12,9,3,13,8,29
SORT_FLAG DB 0
CUR_OFFSET DW BUFFER
CUR_FILE DW ?
END_OFFSET DW ?
PAGES DW ?
PAGE_END DW 21*160+323
COUNT DW 1
LINE DW 323
STAR_DOT_STAR DB '*.*',0
VERIFY_FLAG DB 1
WORDSTAR_BIT DB 7FH
SEARCH_COUNT DW ?
DISPATCH_KEY DB 1,11H,12H,13H,14H,1CH,1FH,20H,2FH,31H,32H,3BH,3CH,3DH,3EH
DB 3FH,40H,41H,42H,43H,44H,47H,48H,49H,4FH,50H,51H,76H,84H
DISPATCH_TABLE DW EXIT, WORDSTAR, SORT_EXT, RENAME, SORT_DATE, VIEW
DW SORT_SIZE, DELETE, VIEW, SORT_NAME, MOVE, VIEW
DW DELETE, RENAME, MOVE, VERIFY, WORDSTAR, SORT_NAME
DW SORT_EXT, SORT_SIZE, SORT_DATE, HOME_BAR, UP_ARROW
DW PG_UP, END_BAR, DN_ARROW, PG_DN, BOTTOM_BAR, TOP_BAR
VIEW_TABLE DW HOME_FILE, UP_LINE, UP_PG, END_FILE
DW DN_LINE, DN_PG, END_FILE, HOME_FILE
DISPLAY_FLAG DB ?
ROW DB 0
FILE_END DW ?
FILE_HANDLE DW ?
LAST_PAGE DW ?
NOT_ENOUGH DB 'Not enough memory$'
INVALID DB 'Invalid directory$'
TOO_MANY DB 'Too many files$'
LOADING DB 'Loading and Sorting directory.',0
LOAD_ONLY DB 'Loading directory.',0
DIRECTORY DB 'Directory of ',0
FILES DB ' Files',0
DELETE_MSG DB ' will be deleted.',0,'Do you wish to delete it? Y/N',0
RENAME_MSG DB 'Enter new name for ',0
MOVE_MSG DB 'Enter new directory for ',0
ON DB ' ON',0
OFF DB 'OFF',0
BS DB 8,32,8,0
FILE_BUFFER EQU 32767-256
SIXTEEN_K EQU 16384
MENU LABEL BYTE
DB 201,20 DUP (205),187,186,' PC Magazine DR.COM ',186
DB 186,' (C) Copr. 1987 ZD ',186,186,' Michael J. Mefford ',186
DB 199,20 DUP (196),182,186,' F1 View (or ',17,196,217,') ',186
DB 186,' F2 Delete ',186,186,' F3 Rename ',186
DB 186,' F4 Move ',186,186,' F5 Confirm ON ',186
DB 186,' F6 WordStar ON ',186,186,' F7 Sort by Name ',186
DB 186,' F8 Sort by Ext. ',186,186,' F9 Sort by Size ',186
DB 186,' F10 Sort by daTe ',186,186,' Esc to Exit ',186
DB 200,20 DUP (205),188,' Use: ',24,32,25,' PgUp PgDn '
DB ' ^PgUp ^PgDn Home End '
;----------------------------------------------------------------------------;
; Some housekeeping first. Since we will be changing the default drive ;
; and directory to the requested drive and directory, we need to save the ;
; current defaults, so they can be restored. If less than 64K, exit. ;
;----------------------------------------------------------------------------;
; CODE AREA
; ---------
BEGINNING: MOV AX,3301H ;Turn Control Break off.
MOV DL,0
INT 21H
CLD ;String moves forward.
MOV AH,19H ;Get current drive.
INT 21H
MOV CURRENT_DISK,AL ;And save.
;---------------------------------------------------------------------;
; More housekeeping. We will be writing directly to the screen buffer ;
; so we need the display card address and the status register. ;
;---------------------------------------------------------------------;
DISPLAY: MOV AX,40H ;Point to the ROM BIOS data area
MOV DS,AX ; and get base address of active
MOV AX,DS:[63H] ; display card.
ADD AX,6 ;Add six to get status register
PUSH CS ;Done there, so restore data segment.
POP DS
MOV STATUS_REG,AX ;Store status register.
CMP AX,3BAH ;Status port of MONO card is 3BAh.
JZ MONO ;If that's what we got, it's MONO
MOV VIDEO_SEG,0B800H ; else COLOR so add 800h.
XOR BH,BH ;Get current attribute
MOV AH,8 ; of display page zero.
INT 10H
MOV NORMAL,AH ;Store it.
XOR AH,1110111B ;Flip color bits.
MOV INVERSE,AH ;Save it.
MOV BAR_ATTRIBUTE,AH
MONO: XOR BH,BH
MOV AH,3 ;Retrieve cursor type.
INT 10H
MOV CURSOR_TYPE,CX
CMP SP,65533 ;Do we have 64K?
MOV DX,OFFSET NOT_ENOUGH
JA PARSE
JMP ERROR_EXIT ;If no, exit.
;----------------------------------------;
; Parse the command line for parameters. ;
;----------------------------------------;
PARSE: CMP BYTE PTR DS:[80H],0 ;Any parameters?
JNZ GET_SWITCH ;If yes, parse.
JMP MESSAGE ;Else, skip.
GET_SWITCH: MOV SI,81H ;Else, point to first character.
NEXT_SWITCH: LODSB ;Get a byte.
CMP AL,13 ;Carriage return?
JZ GET_PARA ;If yes, done here.
CMP AL,'/' ;Is it switch character?
JNZ NEXT_SWITCH ;If no, get next character.
LODSB ;Get switch character.
AND AL,5FH ;Capitalize.
CMP AL,'E' ;If "E", sort by extension.
JNZ CK_SIZE
MOV SORT_OFFSET,4
CK_SIZE: CMP AL,'S' ;If "S", sort by size.
JNZ CK_DATE
MOV SORT_OFFSET,8
CK_DATE: CMP AL,'D' ;If "D", sort by date.
JZ GOT_DATE
CMP AL,'T' ;If "T", sort by date.
JNZ CK_ORIGINAL
GOT_DATE: MOV SORT_OFFSET,12
CK_ORIGINAL: CMP AL,'O' ;If "O", don't sort at all.
JNZ GET_PARA
MOV SORT_FLAG,1
GET_PARA: MOV SI,81H ;Point to first character.
NEXT_PARSE: LODSB
CMP AL,13 ;Carriage return or slash?
JZ MESSAGE ;If yes, done here.
CMP AL,'/'
JZ MESSAGE
CMP AL,32 ;Leading space?
JBE NEXT_PARSE ;If yes, get next byte.
PUSH SI ;Save start.
NEXT_PARA: LODSB
CMP AL,32 ;End of parameter?
JBE END_PARA ;If yes, done here.
CMP AL,'/'
JZ END_PARA
CMP AL,':' ;Drive request?
JNZ NEXT_PARA ;If no, get next byte.
MOV DL,BYTE PTR [SI-2] ;Else, retrieve request.
AND DL,5FH ;Capitalize.
SUB DL,'A' ;Convert to DOS format.
MOV AH,0EH ;And change drive.
INT 21H
JMP SHORT NEXT_PARA ;Find end of parameter.
END_PARA: MOV BYTE PTR DS:[SI-1],0 ;Convert parameter to ASCIIZ.
MOV BL,BYTE PTR DS:[SI-2]
MOV SI,OFFSET CURRENT_DIR ;Get current directory.
CALL GET_DIR
POP DX ;Retrieve start.
DEC DX ;Adjust.
CMP BL,':' ;Is it a drive request?
JZ MESSAGE ;If yes, skip directory change.
CMP BL,32 ;Is it a delimiter?
JBE MESSAGE ;If yes, skip.
MOV AH,3BH ;Change directory.
INT 21H
MOV DX,OFFSET INVALID
JC ERROR_EXIT ;If error, exit.
MESSAGE: CALL CLS ;Clear screen.
CALL CURSOR_OFF ;Cursor off.
MOV SI,OFFSET LOADING ;Display sorting message.
MOV DX,0C19H
CMP SORT_FLAG,1 ;Unless not sorted.
JNZ DISP_MSG
MOV SI,OFFSET LOAD_ONLY ;Then display loading message.
MOV DX,0C1FH
DISP_MSG: CALL DISPLAY_TEXT
MOV DI,OFFSET BUFFER ;Put space character
MOV CX,16000 ; in directory listing
MOV AX,2020H ; buffer.
REP STOSW
;------------------------------------------------------------------;
; Read all the directory filenames and store as records in buffer. ;
;------------------------------------------------------------------;
READ_DIR: MOV DX,OFFSET STAR_DOT_STAR
MOV CX,7
MOV AH,4EH ;Find first matching file.
INT 21H
JC EXIT ;If empty directory, exit.
STORE_NAME: MOV DI,OFFSET BUFFER ;Point to buffer.
MOV BP,FILE_BUFFER-200 ;Reserve 32K for file read buffer
CALL BUFFER_NAME ;Convert to directory format.
FIND_NEXT: MOV AH,4FH ;Find next matching.
INT 21H
JC STORE_COUNT ;If carry, no more names.
INC COUNT ;Increment count of names.
CALL BUFFER_NAME
CMP DI,BP ;Are we encroaching file buffer?
JBE FIND_NEXT ;If no, find next.
MOV DX,OFFSET TOO_MANY ;Else, exit with message.
;-----------------------------------------------------------------------;
; This is the exit routine. Restore the defaults the way we found them. ;
;-----------------------------------------------------------------------;
ERROR_EXIT: MOV AH,9 ;Display error message.
INT 21H
JMP SHORT RESET
EXIT: CALL CLS ;Clear screen.
XOR DX,DX ;Set cursor top left.
CALL SET_CURSOR
CALL CURSOR_ON ;Turn cursor back on.
RESET: MOV DX,OFFSET CURRENT_DIR ;Reset the directory.
MOV AH,3BH
INT 21H
MOV DL,CURRENT_DISK ;Reset the drive.
MOV AH,0EH
INT 21H
INT 20H
;-----------------------------------;
; Store buffer end address and page ;
; end then sort the filenames. ;
;-----------------------------------;
STORE_COUNT: MOV END_OFFSET,DI ;Store ending offset.
ADD DI,40
MOV PAGES,DI ;Also, address for page storage.
MOV BX,COUNT ;Retrieve file count.
CMP BX,21 ;Enough to fill one page?
JAE DO_SORT ;If yes, use default setting.
ADD PAGES,800 ;Else, adjust page storage.
MOV AX,160 ;Calculate last record.
MUL BL
ADD AX,323 ;Add bar offset.
MOV PAGE_END,AX
DO_SORT: CMP SORT_FLAG,1 ;Should we sort or leave original?
JZ READY ;If it was "/O", don't sort.
CALL SORT
;------------------------------------------------------------------------;
; Now, we are ready to get target directory and display it and the menu. ;
;------------------------------------------------------------------------;
READY: MOV DI,OFFSET PURGE_DIR ;Point to storage.
MOV AH,19H
INT 21H ;Get drive.
ADD AL,'A' ;Convert to ASCII.
STOSB
MOV AL,':' ;Add colon.
STOSB
MOV SI,DI ;Get directory.
CALL GET_DIR
CALL REFRESH_DIR ;Display drive, directory, menu.
;-----------------------------------------;
; We are ready for business now. We will ;
; loop here, waiting for user keystrokes. ;
;-----------------------------------------;
GET_KEY: CALL UPDATE_SCREEN
CALL READ_KEY ;Get a keystroke.
MOV BX,AX ;Save returned key.
CMP AH,1 ;Is it Esc or below?
JBE FUNCTION ;If yes, function.
CMP AH,36H ;Is it right shift or above?
JAE FUNCTION ;If yes, function.
CMP AH,1CH ;Is it CR?
JZ FUNCTION ;If yes, function.
MOV AH,2 ;Get shift state.
INT 16H
TEST AL,4 ;Is Ctrl depressed?
JNZ FUNCTION ;If no, check function request.
CALL SEARCH ;Else, search for first letter.
JMP SHORT GET_KEY
FUNCTION: MOV DI,OFFSET DISPATCH_KEY
MOV AL,BH
MOV CX,29 ;29 valid commands.
REPNZ SCASB
JNZ GET_KEY ;If no match, get another.
MOV DI,OFFSET DISPATCH_TABLE+56
SHL CX,1
SUB DI,CX
CALL DS:[DI] ;Else do subroutine.
JMP SHORT GET_KEY ;Update screen; get next command.
;*************;
; SUBROUTINES ;
;*************;
;--------------------------------------------------------------------------;
; These six subroutines control the bar and page of the directory listing. ;
;--------------------------------------------------------------------------;
UP_ARROW: MOV BP,-160 ;Move bar up one line.
JMP SHORT BAR_MOVE
DN_ARROW: MOV BP,160 ;Move bar down one line.
BAR_MOVE: CALL SCROLL_BAR
RET
PG_UP: MOV BP,-40*21 ;Move up 21 lines.
CALL SCROLL
JMP SHORT BOTTOM_BAR
PG_DN: MOV BP,40*21 ;Move down 21 lines.
MOVE_PAGE: CALL SCROLL
JMP SHORT TOP_BAR ;Move bar to top.
HOME_BAR: MOV CUR_OFFSET,OFFSET BUFFER ;Move listing to beginning.
TOP_BAR: MOV SI,323 ;And move bar to top.
CALL MOVE_BAR
RET
END_BAR: MOV BX,END_OFFSET ;Move listing to last page.
SUB BX,21*40
CMP BX,OFFSET BUFFER
JBE BOTTOM_BAR
MOV CUR_OFFSET,BX
BOTTOM_BAR: MOV SI,PAGE_END ;And move bar to bottom.
SUB SI,160
CALL MOVE_BAR
RET
;-----------------------------------------------------------------------;
; This subroutine searches for a filename with a specific first letter. ;
;-----------------------------------------------------------------------;
SEARCH: CMP BL,'a' ;Capitalize if lower case.
JB SEARCH_IT
CMP BL,'z'
JA SEARCH_IT
AND BL,5FH
SEARCH_IT: CALL GET_NAME ;Get current position.
XOR DX,DX ;Zero out file counter.
MOV DI,SI ;Store current position in DI.
MOV SI,OFFSET BUFFER ;Point to top of listing.
CMP BYTE PTR [DI],BL ;Are we currently at a match?
JNZ NEXT_SEARCH ;If no, start from top.
FIND_START: INC DX ;Increment count.
ADD SI,40 ;Increment record.
CMP SI,DI ;New record?
JBE FIND_START ;If no, find it.
NEXT_SEARCH: CMP BYTE PTR [SI],BL ;Got a match?
JZ FOUND_IT ;If yes, process.
INC_SEARCH: ADD SI,40 ;Else, point to next record.
INC DX
CMP BYTE PTR [SI],32 ;End of listing?
JNZ NEXT_SEARCH ;If no, keep searching.
CALL BEEP ;No matches, so beep.
RET
FOUND_IT: MOV CX,COUNT ;Retrieve file count.
SUB CX,DX ;Subtract search count.
MOV SEARCH_COUNT,CX ;And store.
MOV CL,NORMAL ;Turn off bar for now.
MOV BAR_ATTRIBUTE,CL
CALL END_BAR ;First move to end.
JMP SHORT FIND_IT
NEXT_FIND: CALL UP_ARROW ;Move up to matching filename.
FIND_IT: DEC SEARCH_COUNT
JNZ NEXT_FIND
MOV CL,INVERSE ;Turn bar back on and display.
MOV BAR_ATTRIBUTE,CL
XOR BP,BP
CALL SCROLL_BAR
RET
;------------------------------------------------------------;
; This subroutine displays the highlighted file for viewing. ;
;------------------------------------------------------------;
VIEW: CALL GET_NAME ;Get the file name.
MOV DX,OFFSET FILE_NAME ;Open the file.
MOV AX,3D00H
INT 21H
MOV FILE_HANDLE,AX ;Save filehandle.
CALL FIRST_READ
MOV LAST_PAGE,OFFSET FILE_BUFFER+SIXTEEN_K
MOV BP,PAGES ;Initialize page pointer.
MOV ROW,0 ;And row pointer.
CALL CLS ;Clear screen.
GET_VIEW: MOV SI,LAST_PAGE ;Get top of current page.
MOV BH,ROW ;Get row offset into page.
CMP BH,0 ;Is it row zero?
JZ NEXT_VIEW ;If yes, skip.
MOV DISPLAY_FLAG,0 ;No display.
PAGE_OFFSET: CALL LINES
DEC BH
JNZ PAGE_OFFSET
NEXT_VIEW: MOV BH,25 ;Now display 25 lines.
XOR DI,DI ;Start at top left corner.
MOV DISPLAY_FLAG,1 ;Display.
VIEW_DISPLAY: CALL LINES
DEC BH
JNZ VIEW_DISPLAY
VIEW_COMMAND: CALL READ_KEY ;Get a keystroke.
CMP AH,1 ;Is it Esc?
JZ VIEW_END ;If yes, exit view.
CMP AH,1CH ;Is it carriage return?
JZ VIEW_END ;If yes, exit view.
CMP AH,3BH ;Is it F1?
JZ VIEW_END ;If yes, exit.
CMP AH,20H ;Is it "D"?
JZ VIEW_DELETE ;If yes, go to delete function.
CMP AH,3CH ;Is it F2?
JNZ CK_RENAME ;If no, check if rename request.
VIEW_DELETE: CALL VIEW_REQUEST ;Else, close file.
JMP DELETE ;Go to delete function.
CK_RENAME: CMP AH,13H ;Is it "R"?
JZ VIEW_RENAME ;If yes, go to rename function.
CMP AH,3DH ;Is it F3?
JNZ CK_MOVE ;If no, check if move request.
VIEW_RENAME: CALL VIEW_REQUEST
JMP RENAME
CK_MOVE: CMP AH,32H ;Is it "M"?
JZ VIEW_MOVE ;If yes, go to move function.
CMP AH,3EH ;Is it F4?
JNZ GET_DISPATCH ;If no, get dispatch table.
VIEW_MOVE: CALL VIEW_REQUEST
JMP MOVE
GET_DISPATCH: MOV DI,OFFSET DISPATCH_KEY+21
MOV AL,AH
MOV CX,8 ;8 valid commands.
REPNZ SCASB
JNZ VIEW_COMMAND ;If no, match, get next stroke.
MOV DI,OFFSET VIEW_TABLE+14
SHL CX,1
SUB DI,CX
CALL DS:[DI] ;Do subroutine.
JC VIEW_COMMAND ;Carry indicates no screen update.
JMP GET_VIEW ;Else, update and get next command.
VIEW_END: MOV BX,FILE_HANDLE ;Close the file.
MOV AH,3EH
INT 21H
CALL REFRESH_DIR ;Restore menu.
RET
VIEW_REQUEST: CALL VIEW_END ;If request of another function,
CALL UPDATE_SCREEN ; close file and update screen.
RET
;----------------------------------------------------------------------;
; These six subroutines control the page and starting row of the view. ;
;----------------------------------------------------------------------;
UP_LINE: CMP ROW,0 ;Are we at row zero?
JNZ DEC_ROW ;If no, decrement one row.
CMP BP,PAGES ;Else, are we at first page?
STC
JZ UP_LINE_END ;If yes, no change.
CALL UP_PG ;Else, move up one page.
MOV ROW,25 ;And move starting row to 25.
DEC_ROW: DEC ROW ;Decrement row.
CLC ;Flag to update screen.
UP_LINE_END: RET
DN_LINE: CALL CK_FILE_END ;Are we at end of file?
JNC CK_ROW ;If no, check row.
RET ;Else, return.
CK_ROW: CMP ROW,24 ;Are we at last row?
JB INC_ROW ;If no, increment row.
CALL DN_PG ;Else, page down.
MOV ROW,-1 ;And move row to top.
INC_ROW: INC ROW
CLC
DN_LINE_END: RET
UP_PG: CMP BP,PAGES ;Are we already at first page?
JNZ DEC_PG ;If no, decrement page.
CMP ROW,0 ;Are we at first row?
STC
JZ UP_PG_END ;If yes, no update.
MOV ROW,0 ;Else move to first row.
JMP SHORT UPDATE_PAGE
DEC_PG: MOV SI,LAST_PAGE ;Get current page.
SUB SI,DS:[BP] ;Subtract difference to prev page.
CMP SI,OFFSET FILE_BUFFER ;Beyond top of buffer?
JAE UP_PG_RET ;If no, page up.
CALL BACKWARD ;Else, read in previous 16K
JMP SHORT DEC_PG ;Try again.
UP_PG_RET: DEC BP
DEC BP ;Decrement page pointer.
MOV LAST_PAGE,SI ;Store new starting position.
UPDATE_PAGE: CLC
UP_PG_END: RET
DN_PG: CMP BP,65535-256 ;Out of room for page storage?
JAE NOUPDATE_PG ;If yes, skip.
MOV SI,LAST_PAGE ;Else, retrieve current page.
MOV DISPLAY_FLAG,0 ;No display.
MOV BH,25 ;Move up 25 lines.
NEXT_PAGE: CALL LINES
DEC BH
JNZ NEXT_PAGE
CALL CK_FILE_END ;End of file?
JC NOUPDATE_PG ;If yes, no update.
INC_PG: MOV DX,LAST_PAGE ;Else, save current offset.
MOV LAST_PAGE,SI ;Store new offset.
MOV AX,SI
SUB AX,DX ;Get difference between pages.
INC BP ;Increment page storage.
INC BP
MOV DS:[BP],AX ;And store.
CLC
DN_PG_END: RET
NOUPDATE_PG: STC
RET
HOME_FILE: CALL UP_PG ;Page up until top of file.
JNC HOME_FILE
CLC
RET
END_FILE: CALL DN_PG ;Page down until end of file.
JNC END_FILE
CLC
RET
;----------------------------------------------------------------;
; This subroutine checks to see if end of file has been reached. ;
;----------------------------------------------------------------;
CK_FILE_END: CMP SI,FILE_END
JB NOT_FILE_END
CMP FILE_END,OFFSET FILE_BUFFER+(SIXTEEN_K * 2)
JAE NOT_FILE_END
STC
RET
NOT_FILE_END: CLC
RET
;----------------------------------------------------------------;
; This subroutine formats the text into lines. A line is marked ;
; by either a carriage return or reaching the last column (80). ;
;----------------------------------------------------------------;
LINES: MOV CX,80 ;80 columns.
NEXT_LINES: CMP SI,FILE_END ;If end of file, pad with spaces.
JB GET_LINES
CMP FILE_END,OFFSET FILE_BUFFER+ (SIXTEEN_K * 2)
JB PAD_SPACES
PUSH BX ;If end of buffer, save
PUSH CX ; our pointers and
PUSH DI ; read next 16K.
CALL FORWARD
POP DI ;Restore pointers.
POP CX
POP BX
GET_LINES: LODSB ;Get a byte.
AND AL,WORDSTAR_BIT ;Strip high bit for WordStar?
CMP AL,13 ;Carriage return?
JZ PAD_SPACES ;If yes, pad balance of line.
CMP AL,9 ;Is it tab character?
JZ TAB ;If yes, tab.
CMP AL,10 ;Is it linefeed?
JZ NEXT_LINES ;If yes, skip.
PUSH CX ;Save counter.
MOV CX,1 ;Else, display one character.
CALL CK_DISPLAY
POP CX
NEXT_BYTES: LOOP NEXT_LINES ;Get next byte.
CMP BYTE PTR [SI],13 ;Is this a eighty column line?
JNZ END_LINES ;If no, skip.
INC SI ;Else, bump pointer past CR.
END_LINES: RET
TAB: PUSH CX ;Save counter.
DEC CX ;Adjust column counter.
AND CX,7 ;Get bottom three bits.
INC CX ;Adjust.
PUSH CX
CALL PAD_SPACES ;Move to next tab position.
POP AX
POP CX
SUB CX,AX ;Adjust counter.
JNZ NEXT_LINES ;Next byte if not column 80.
RET
PAD_SPACES: MOV AL,32 ;Space character.
CK_DISPLAY: CMP DISPLAY_FLAG,1 ;Are we to write it to screen?
JNZ CK_DISP_END ;If no, return.
MOV BL,AL
WRITE_VIEW: CALL WRITE_SCREEN ;Else, write CX spaces.
LOOP WRITE_VIEW
CK_DISP_END: RET
;-------------------------------------------------------------------;
; These two subroutines read either the next or previous 16K bytes. ;
;-------------------------------------------------------------------;
FORWARD: SUB LAST_PAGE,SIXTEEN_K ;Adjust current page offset.
XOR CX,CX ;Move file pointer
MOV DX,SIXTEEN_K ; forward 16K.
CALL MOVE_POINTER
FIRST_READ: MOV SI,OFFSET FILE_BUFFER+SIXTEEN_K
MOV DI,OFFSET FILE_BUFFER ;Move second half of buffer
CALL MOVE_BUFFER ; to first half and read 16K.
MOV CX,-1 ;Move file pointer back.
NEG DX
CALL MOVE_POINTER
RET
BACKWARD: ADD LAST_PAGE,SIXTEEN_K ;Adjust current page offset.
MOV CX,-1 ;Move pointer back 32K.
MOV DX,- (SIXTEEN_K * 2)
CALL MOVE_POINTER
MOV SI,OFFSET FILE_BUFFER ;Move first half of
MOV DI,OFFSET FILE_BUFFER+SIXTEEN_K ; buffer to second
CALL MOVE_BUFFER ; and read 16K.
RET
MOVE_POINTER: MOV BX,FILE_HANDLE
MOV AX,4201H ;Move file pointer.
INT 21H
RET
MOVE_BUFFER: MOV DX,SI ;Save pointer.
MOV CX,SIXTEEN_K / 2 ;Move 8K words (16K bytes).
REP MOVSW
MOV BX,FILE_HANDLE
MOV CX,SIXTEEN_K ;Read 16K.
MOV AH,3FH
INT 21H
MOV SI,DX
MOV DX,AX
ADD AX,OFFSET FILE_BUFFER+SIXTEEN_K
MOV FILE_END,AX ;Store end of buffer offset.
RET
;-----------------------------------------------;
; This subroutine deletes the highlighted file. ;
;-----------------------------------------------;
DELETE: CALL GET_NAME ;Format the name for DOS.
JC DELETE_ERROR ;If yes, skip.
CMP VERIFY_FLAG,0 ;Are we to warn before deleting?
JZ DELETE_FILE ;If no, skip.
MOV SI,OFFSET FILE_NAME ;Else, display warning message.
MOV DX,162DH
CALL DISPLAY_TEXT
MOV SI,OFFSET DELETE_MSG
CALL GET_TEXT
MOV DX,172DH
CALL DISPLAY_TEXT
QUERY: CALL READ_KEY ;Get a keystroke.
CMP AH,31H ;Is it "N"?
JZ DELETE_END ;If yes, exit delete.
CMP AH,1 ;Is it Esc?
JZ DELETE_END ;If yes, exit delete.
CMP AH,15H ;Is it "Y"?
JZ DELETE_FILE ;If yes, delete
CALL BEEP ;Else, beep.
JMP SHORT QUERY ;And get another keystroke.
DELETE_FILE: MOV DX,OFFSET FILE_NAME ;Delete the file.
MOV AH,41H
INT 21H
JC DELETE_ERROR
CALL REMOVE_FILE ;Remove the file from the listing.
DELETE_END: CALL CLEAR_MSG ;Remove warning message.
RET
DELETE_ERROR: CALL BEEP ;Beep if error.
CALL CLEAR_MSG
RET
;-----------------------------------------------;
; This subroutine renames the highlighted file. ;
;-----------------------------------------------;
RENAME: CALL GET_NAME ;Format name for DOS.
JC RENAME_ERROR
MOV DX,162CH ;Display rename message.
MOV SI,OFFSET RENAME_MSG
CALL DISPLAY_TEXT
MOV SI,OFFSET FILE_NAME
CALL GET_TEXT
MOV DX,172CH
CALL CLEAR_OLD ;Remove last entry.
NEW_NAME: CALL READ_KEY ;Get a character.
CMP AL,27 ;Is it Esc?
JZ RENAME_END ;Is yes, exit rename.
CMP AL,':' ;Ignore ":\?* ".
JZ NEW_NAME
CMP AL,' '
JZ NEW_NAME
CMP AL,'\'
JZ NEW_NAME
CMP AL,'?'
JZ NEW_NAME
CMP AL,'*'
JZ NEW_NAME
CMP AL,13 ;Is it carriage return?
JZ RENAME_IT ;If yes, rename it.
CMP AL,8 ;Is it backspace?
JNZ NOT_BS1
CALL MOVE_BS ;If yes, backspace.
JMP SHORT NEW_NAME
NOT_BS1: CMP AL,32 ;Is it space or above?
JB NEW_NAME ;If no, ignore.
CMP DI,8CH ;End of entry field?
JZ NEW_NAME ;If yes, ignore.
STOSB ;Else, store byte.
CALL WRITE_TEXT ;And write it to screen.
JMP SHORT NEW_NAME ;Get next keystroke.
RENAME_IT: CALL RENAME_FILE ;Rename the file.
JC RENAME_ERROR ;Beep if illegal.
MOV DX,80H ;Else, place new name in listing.
MOV CX,7
MOV AH,4EH
INT 21H
MOV DI,CUR_FILE
CALL BUFFER_NAME
RENAME_END: CALL CURSOR_OFF ;Turn cursor back off.
CALL CLEAR_MSG ;And clear rename message.
RENAME_RET: RET
RENAME_ERROR: CALL BEEP ;Illegal entry exit.
CALL CURSOR_OFF
CALL CLEAR_MSG
RET
;----------------------------------------------------------------;
; This subroutine moves the highlighted file to a new directory. ;
;----------------------------------------------------------------;
MOVE: CALL GET_NAME ;Format the name for DOS.
JC MOVE_ERROR
MOV DX,162BH ;Display the move message.
MOV SI,OFFSET MOVE_MSG
CALL DISPLAY_TEXT
MOV SI,OFFSET FILE_NAME
CALL GET_TEXT
MOV DX,172BH
CALL CLEAR_OLD ;Remove previous entry.
NEW_DIR: CALL READ_KEY ;Get a keystroke.
CMP AL,27 ;Is it Esc?
JZ MOVE_END ;If yes, exit move.
CMP AL,':' ;Is it ":"?
JZ NEW_DIR ;If yes, skip
CMP AL,13 ;Is it carriage return?
JZ MOVE_IT ;If yes, move it.
CMP AL,8 ;If it backspace?
JNZ NOT_BS2
CALL MOVE_BS ;If yes, backspace.
JMP SHORT NEW_DIR
NOT_BS2: CMP AL,32 ;Is it space or above?
JB NEW_DIR ;If no, ignore.
CMP DI,0A4H ;Is it at end of entry field?
JZ NEW_DIR ;If yes, ignore.
STOSB ;Else, store the byte.
CALL WRITE_TEXT ;And write it to screen.
JMP SHORT NEW_DIR ;Get next keystroke.
MOVE_IT: CMP BYTE PTR DS:[80H],32 ;No entry?
JZ MOVE_ERROR ;If yes, error.
MOV SI,OFFSET FILE_NAME ;Point to filename.
MOV AL,'\'
CMP DS:[DI-1],AL ;Did user add "\"?
JZ ADD_FILENAME ;If yes, skip.
STOSB ;Else, we have to add it.
ADD_FILENAME: MOVSB ;And filename to path.
CMP BYTE PTR DS:[SI],0
JNZ ADD_FILENAME
CALL RENAME_FILE ;Rename it.
JC MOVE_ERROR ;Beep if illegal.
CALL REMOVE_FILE ;Else remove from listing.
MOVE_END: CALL CURSOR_OFF ;Cursor back off.
CALL CLEAR_MSG ;Clear move message.
RET
MOVE_ERROR: CALL BEEP ;Illegal move exit.
CALL CURSOR_OFF
CALL CLEAR_MSG
RET
;-----------------------------------------------------------------------------;
; This subroutine toggles the delete confirm and WordStar message on and off. ;
;-----------------------------------------------------------------------------;
VERIFY: XOR VERIFY_FLAG,1 ;Toggle flag.
MOV DI,OFFSET MENU+(9*22)+16 ;Point to menu.
MOV SI,OFFSET ON ;Assume "ON".
CMP VERIFY_FLAG,1 ;Is it on?
JZ TOGGLE ;If yes, store.
MOV SI,OFFSET OFF ;Else, store "OFF".
JMP SHORT TOGGLE
WORDSTAR: XOR WORDSTAR_BIT,80H ;Toggle flag.
MOV DI,OFFSET MENU+(10*22)+16 ;Point to menu.
MOV SI,OFFSET ON ;Assume "ON".
CMP WORDSTAR_BIT,7FH ;Is it on?
JZ TOGGLE ;If yes, store.
MOV SI,OFFSET OFF ;Else, store "OFF".
TOGGLE: MOV CX,3
REP MOVSB
CALL REFRESH_MENU ;Display.
RET
;------------------------------------------------------------------------;
; These four subroutines control in which column the sorting will start. ;
;------------------------------------------------------------------------;
SORT_NAME: MOV SORT_OFFSET,0
JMP SHORT SORT_MSG
SORT_EXT: MOV SORT_OFFSET,4
JMP SHORT SORT_MSG
SORT_SIZE: MOV SORT_OFFSET,8
JMP SHORT SORT_MSG
SORT_DATE: MOV SORT_OFFSET,12
SORT_MSG: MOV DX,1633H
MOV SI,OFFSET LOADING+12
CALL DISPLAY_TEXT
;------------------------------------------;
; This subroutine does the actual sorting. ;
;------------------------------------------;
SORT: CMP COUNT,1
JZ SORT_RETURN
MOV DX,END_OFFSET ;End of filenames in DX.
SUB DX,40
MOV BP,SORT_OFFSET
NEXT_PASS: MOV SORT_FLAG,0
MOV BX,OFFSET BUFFER ;Point to start of buffer.
NEXT_SORT: MOV SI,BX ;Source and destination.
ADD SI,SORT_TABLE[BP]
MOV DI,SI
ADD DI,40
CMP BP,12 ;Is it special case of date?
JZ DO_DATE ;If yes, go do it.
MOV CX,SORT_TABLE[BP+2]
COMPARE: REPZ CMPSB ;Compare filenames.
JBE END_SORT ;If already in order, skip.
SWAP: MOV SI,BX ;Else, recover pointers.
MOV DI,BX
ADD DI,40
MOV CX,20 ;Exchange the records.
NEXT_SWAP: MOV AX,[DI]
MOVSW
MOV [SI-2],AX
LOOP NEXT_SWAP
MOV SORT_FLAG,1 ;Flag that exchange was made.
END_SORT: ADD BX,40 ;Point to next record.
CMP BX,DX ;End of top?
JB NEXT_SORT ;If no, bubble sort next.
SUB DX,40 ;Else, move top down one record.
CMP SORT_FLAG,0 ;Was there exchange made?
JNZ NEXT_PASS ;If yes, another pass.
SORT_RETURN: CALL CLEAR_MSG
RET
DO_DATE: MOV CX,2 ;Compare year first.
REPZ CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
SUB SI,8 ;Else, adjust and do month/day.
SUB DI,8
MOV CX,5
REPZ CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
ADD SI,10 ;Else, adjust and do meridian.
ADD DI,10
CMPSB
JA SWAP ;If above, swap.
JNZ END_SORT
SUB SI,6 ;Else, adjust and do time.
SUB DI,6
MOV CX,5
CMP WORD PTR [SI],3231H ;Is it special case "12:"?
JZ CK_MERIDIAN ;If yes, see if same.
CMP WORD PTR [DI],3231H ;Is destination "12:"?
JNZ COMPARE ;If no, normal compare.
JMP SWAP ;Else, swap.
CK_MERIDIAN: CMPSW ;Are both "12:"?
JNZ END_SORT ;If no, next record.
MOV CX,3 ;Else compare minutes.
JMP SHORT COMPARE
;--------------------------------------------------------------------------;
; This subroutine gets the highlighted file and converts it to DOS format. ;
;--------------------------------------------------------------------------;
GET_NAME: MOV SI,CUR_OFFSET ;Get top of page.
MOV AX,LINE ;Get location of bar.
SUB AX,323 ;Adjust.
MOV CL,2 ;Convert to byte pointer.
SHR AX,CL
ADD SI,AX ;Add to current offset.
MOV CUR_FILE,SI ;And save pointer.
PUSH SI
MOV DI,OFFSET FILE_NAME ;Store the first eight characters.
MOV CX,8
CALL STORE_BYTES
INC SI
CMP BYTE PTR DS:[SI],32 ;End of name?
JZ END_NAME ;If yes, done here.
MOV AL,'.' ;Else, add dot.
STOSB
MOV CX,3 ;Three possible characters
CALL STORE_BYTES ; as extension.
END_NAME: MOV BYTE PTR DS:[DI],0 ;Convert to ASCIIZ.
POP SI
CMP BYTE PTR [SI+39],'H' ;Is it a hidden file?
STC
JZ NAME_ERROR ;If yes, indicate so.
CLC
NAME_ERROR: RET
STORE_BYTES: LODSB ;Get a character.
CMP AL,32 ;If it's space, skip.
JZ SKIP_STORE
STOSB
SKIP_STORE: LOOP STORE_BYTES
RET
;-----------------------------------------------------------;
; This subroutine moves and turns the cursor on and removes ;
; the last user entry in preparation for new input. ;
;-----------------------------------------------------------;
CLEAR_OLD: CALL SET_CURSOR ;Move cursor.
CALL CURSOR_ON ;Turn it on.
MOV DI,80H ;Write spaces over old entry.
MOV AX,2020H
MOV CX,18
REP STOSW
MOV DI,80H ;Initiate pointer for entry.
RET
;-----------------------------;
; This subroutine backspaces. ;
;-----------------------------;
MOVE_BS: CMP DI,80H ;At beginning of field?
JZ MOVE_BS_END ;If yes, skip.
DEC DI ;Else, decrement pointer.
MOV SI,OFFSET BS ;Erase last character.
CALL GET_TEXT
MOVE_BS_END: RET
;--------------------------------------------;
; This subroutine renames or moves the file. ;
;--------------------------------------------;
RENAME_FILE: MOV BYTE PTR DS:[DI],0 ;Convert to ASCIIZ.
MOV DX,OFFSET FILE_NAME ;Point to old name.
MOV DI,80H
MOV AH,56H ;Rename.
INT 21H
RET
;------------------------------------------------------------------;
; This subroutine removes the filename from the directory listing. ;
;------------------------------------------------------------------;
REMOVE_FILE: MOV DI,CUR_FILE ;Point to filename.
MOV SI,DI ;Move all the records
ADD SI,40 ; that follow up one.
NEXT_RECORD: MOV CX,20
REP MOVSW
CMP DI,END_OFFSET
JB NEXT_RECORD
SUB DI,40
MOV END_OFFSET,DI ;Store new end.
XOR BP,BP
CALL SCROLL ;Update the screen.
DEC COUNT ;Decrement file count.
JNZ MORE_FILES ;If empty, exit.
JMP EXIT
MORE_FILES: CMP COUNT,21 ;Full page?
JAE REMOVE_END ;If yes, skip.
SUB PAGE_END,160 ;Else, adjust page end.
MOV SI,PAGE_END
SUB SI,160
CMP SI,LINE ;Is bar below directory listing?
JA REMOVE_END ;If no, skip.
CALL MOVE_BAR ;Else, move bar up one line.
REMOVE_END: CALL FILE_COUNT ;Update file count on screen.
RET
;----------------------------------------------;
; This subroutine displays the count of files. ;
;----------------------------------------------;
FILE_COUNT: MOV DI,OFFSET FILES ;Blank out previous count.
MOV AX,2020H
STOSW
MOV AX,COUNT
MOV BL,10 ;Convert to decimal.
STD ;Reverse direction.
NEXT_COUNT: DIV BL
XCHG AL,AH
ADD AL,'0' ;Convert to ASCII.
STOSB ;Store the remainder.
XCHG AL,AH
XOR AH,AH
CMP AX,0 ;Are we done?
JNZ NEXT_COUNT
CLD ;Back to forward direction.
MOV DX,180EH ;Row 24; column 13.
MOV SI,OFFSET FILES ;Display file count.
CALL DISPLAY_TEXT
RET
;----------------------------------------------------------------------------;
; This subroutine displays the current directory, menu, and number of files. ;
;----------------------------------------------------------------------------;
REFRESH_DIR: CALL CLS ;Clear the screen.
REFRESH_MENU: MOV SI,OFFSET MENU ;Point to menu position.
MOV DI,(2*160)+98 ;And to screen position.
MOV BH,19 ;Display 19 lines of menu.
NEXT_REFRESH: MOV CX,22 ;22 characters per line.
NEXT_MENU: LODSB
MOV BL,AL
CALL WRITE_SCREEN
LOOP NEXT_MENU
ADD DI,116 ;Next line.
DEC BH
JNZ NEXT_REFRESH
MOV DX,4
MOV SI,OFFSET DIRECTORY ;Display "Directory ".
CALL DISPLAY_TEXT
MOV SI,OFFSET PURGE_DIR ;Display working directory.
CALL GET_TEXT
CALL FILE_COUNT ;Display file count.
MOV BL,INVERSE ;Put up cursor bar.
CALL BAR
RET
;-------------------------------------;
; This subroutine scrolls the screen. ;
;-------------------------------------;
SCROLL: MOV SI,CUR_OFFSET ;Get current offset.
ADD SI,BP ;Add requested direction.
CK_LOWER: CMP SI,OFFSET BUFFER ;If above start check upper limit.
JAE UPPER_LIMIT
LOWER_LIMIT: MOV CUR_OFFSET,OFFSET BUFFER ;Else, make it start.
JMP SHORT SCROLL_RETURN ;And update screen.
UPPER_LIMIT: MOV BX,END_OFFSET ;See if beyond end of
CMP BX,OFFSET BUFFER+21*40 ; directory listing as well.
JA CK_UPPER
MOV CUR_OFFSET,OFFSET BUFFER
JMP SHORT SCROLL_RETURN
CK_UPPER: SUB BX,21*40
CMP SI,BX
JBE END_SCROLL
MOV SI,BX
END_SCROLL: MOV CUR_OFFSET,SI ;Update current offset.
SCROLL_RETURN: RET
;--------------------------------------------------;
; This subroutine scrolls the bar if between start ;
; and end of page. Otherwise the page is scrolled. ;
;--------------------------------------------------;
SCROLL_BAR: MOV SI,LINE ;Get current line.
ADD SI,BP ;Add requested line.
MOV BP,-40 ;Assume below beginning.
CMP SI,323 ;Is it?
JB SCROLL_PAGE ;If yes, scroll page instead.
MOV BP,40 ;Do the same for end of page.
CMP SI,PAGE_END
JAE SCROLL_PAGE
CALL MOVE_BAR
RET
SCROLL_PAGE: CALL SCROLL
RET
;----------------------------------------------------;
; This subroutine does the actual moving of the bar. ;
;----------------------------------------------------;
MOVE_BAR: MOV BL,NORMAL ;Remove old bar.
CALL BAR
MOV LINE,SI ;And move bar to new line.
MOV BL,BAR_ATTRIBUTE
CALL BAR
RET
BAR: MOV DI,LINE ;Retrieve line.
MOV CX,39 ;Bar length 39.
NEXT_BAR: CALL WRITE_SCREEN ;Write the attribute.
LOOP NEXT_BAR
RET
;-------------------------------------------------;
; This subroutine displays the directory listing. ;
;-------------------------------------------------;
UPDATE_SCREEN: XOR BP,BP
MOV SI,CUR_OFFSET ;Retrieve starting offset.
MOV DI,2*160+2 ;Point to row two of screen.
MOV BH,21 ;21 lines to write.
NEXT_WRITE: MOV CX,40 ;40 characters per line.
NEXT_CHAR: LODSB ;Get a byte.
MOV BL,AL ;Save it in BL.
CALL WRITE_SCREEN ;Write them.
LOOP NEXT_CHAR
ADD DI,80 ;Bump pointer to next line.
DEC BH ;Do all 21 lines.
JNZ NEXT_WRITE
RET
;------------------------------------------------------------;
; This subroutine displays the directory by writing directly ;
; to the screen buffer. To avoid screen noise (snow) on the ;
; color card, the horizontal retrace has to be monitored. ;
;------------------------------------------------------------;
WRITE_SCREEN: MOV DX,STATUS_REG ;Retrieve status register.
MOV AX,VIDEO_SEG ;Point to screen segment.
MOV ES,AX
HORZ_RET: IN AL,DX ;Get status.
TEST AL,1 ;Is it low?
JNZ HORZ_RET ;If not, wait until it is.
CLI ;No more interrupts.
WAIT: IN AL,DX ;Get status.
TEST AL,1 ;Is it high?
JZ WAIT ;If no, wait until it is.
MOV AL,BL ;Retrieve character; now it's OK
STOSB ; to write to screen buffer.
STI ;Interrupts back on.
INC DI ;Bump pointer past attribute.
PUSH CS
POP ES
RET ;Return
;-----------------------------------------------------------------------;
; These two subroutines clear either the messages or the entire screen. ;
;-----------------------------------------------------------------------;
CLEAR_MSG: MOV CX,162BH ;Row 22; column 43.
MOV DX,174FH ;Row 23; column 79.
JMP SHORT CLEAR_WINDOW
CLS: XOR CX,CX
MOV DX,184FH ;Entire screen.
CLEAR_WINDOW: PUSH BP
PUSH BX
MOV BH,NORMAL ;Clear with original attribute.
MOV AX,600H
INT 10H
POP BX
POP BP
RET
;-----------------------------------------;
; These subroutines display the messages. ;
;-----------------------------------------;
DISPLAY_TEXT: CALL SET_CURSOR ;Move cursor.
GET_TEXT: LODSB
CMP AL,0 ;Zero marks end of string.
JZ END_TEXT
CALL WRITE_TEXT
JMP SHORT GET_TEXT
END_TEXT: RET
WRITE_TEXT: PUSH SI ;BIOS does not save SI.
MOV AH,0EH ;Write teletype.
INT 10H
POP SI
RET
;---------------------------------------------------------;
; These four subroutines move the cursor, get the current ;
; directory, beep the speaker or get a keystroke. ;
;---------------------------------------------------------;
SET_CURSOR: PUSH SI
XOR BH,BH ;Page zero.
MOV AH,2 ;Set cursor.
INT 10H
POP SI
RET
GET_DIR: MOV BYTE PTR [SI],'\' ;DOS doesn't preface directory
INC SI ; with slash so we must.
XOR DL,DL
MOV AH,47H ;Retrieve default directory.
INT 21H
RET
BEEP: MOV DL,7 ;Beep via DOS.
MOV AH,2
INT 21H
RET
READ_KEY: MOV AH,0 ;Retrieve keystroke via BIOS.
INT 16H
RET
;-----------------------------------------------;
; These subroutines turn the cursor off and on. ;
;-----------------------------------------------;
CURSOR_OFF: MOV CX,2000H
JMP SHORT SET_TYPE
CURSOR_ON: MOV CX,CURSOR_TYPE
SET_TYPE: MOV AH,1
INT 10H
RET
;--------------------------------------------------;
; This long subroutine stores the filename in DIR ;
; format. That is, filename, bytes, date and time. ;
;--------------------------------------------------;
BUFFER_NAME: MOV SI,158 ;Point to filename.
MOV CX,12 ;Store 12 bytes of filename.
NEXT_STORE: LODSB ;Get a byte.
CMP AL,0 ;End of filename?
JZ END_STORE ;If yes, finish with blanks.
CMP AL,'.' ;Is it the period?
JNZ STORE_BYTE ;If no, store.
SUB CX,3 ;Else store 3 spaces.
MOV AL,32
REP STOSB
ADD CX,3
JMP SHORT NEXT_STORE ;Get next byte.
STORE_BYTE: STOSB ;Store byte.
LOOP NEXT_STORE ;Get next byte.
END_STORE: MOV AL,32 ;Pad balance with spaces.
REP STOSB
FILE_SIZE: PUSH DI ;Save pointer.
ADD DI,8 ;Move to end of bytes field.
MOV DX,DS:[154] ;Retrieve high and low words
MOV AX,DS:[156] ; of bytes.
MOV BX,10 ;Convert to decimal; divide by 10.
STD ;Reverse direction.
NEXT_SIZE: MOV CX,DX ;Low word in CX.
XOR DX,DX ;Zero in high half.
DIV BX ;Convert to decimal.
XCHG AX,CX ;Retrieve low word.
DIV BX
XCHG AX,DX ;Retrieve remainder.
ADD AL,'0' ;Convert to ASCII.
STOSB ;Store it.
MOV AX,CX ;Are we done?
OR CX,DX
JNZ NEXT_SIZE ;If no, divide again.
CLD ;Back to forward direction.
POP DI ;Retrieve pointer.
ADD DI,11 ;Move to date field.
DATE: MOV DX,DS:[152] ;Retrieve date.
MOV AX,DX
MOV CL,5 ;Shift to lowest bits.
ROR AX,CL
AND AX,0FH ;Mask off all but month.
MOV CL,0FFH ;Flag as no leading zeros.
MOV CH,'-' ;Delimiting character.
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date.
AND AX,1FH ;Mask off all but day.
MOV CL,0 ;Flag include leading zeros.
MOV CH,'-'
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date for last time.
MOV CL,9
ROR AX,CL
AND AX,7FH ;Mask off all but year.
ADD AX,80 ;Adjust to ASCII.
CMP AX,100 ;Past year 2000?
JB DISPLAY_DATE ;If no, display. Else, adjust for
SUB AX,100 ; next century. (Planning ahead!)
DISPLAY_DATE: MOV CL,0 ;Display leading zeros.
MOV CH,32
CALL STORE_WORD ;Store it.
TIME: INC DI ;Move to time field.
MOV DX,DS:[150] ;Retrieve time.
MOV AX,DX
MOV CL,11 ;Shift to hours bits.
ROR AX,CL
AND AX,1FH ;Mask off all but hours.
PUSH AX
CMP AX,12 ;Past noon?
JBE MERIDIAN
SUB AX,12 ;If yes, adjust.
MERIDIAN: CMP AX,0 ;Midnight?
JNZ NOT_MIDNIGHT
MOV AX,12 ;If yes, adjust.
NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
MOV CH,':'
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve time.
MOV CL,5 ;Shift to minutes bits.
ROR AX,CL
AND AX,3FH ;Mask off all but minutes.
MOV CL,0
POP DX ;Retrieve hours.
MOV CH,'p' ;Assume PM.
CMP DX,12 ;Is it PM?
JAE PM
MOV CH,'a' ;If no, AM.
PM: CALL STORE_WORD ;Store it.
MOV AL,'H'
TEST BYTE PTR DS:[149],6 ;Is it a hidden or system file?
JZ NOT_HIDDEN
STOSB ;If yes, tack on an "H".
RET
NOT_HIDDEN: INC DI
RET
;-------------------------------;
STORE_WORD: DIV BL ;Divide by ten.
ADD AX,'00' ;Convert to ASCII.
CMP CL,0 ;Are we to display leading zero?
JZ STORE_IT ;If yes, store as is.
CMP AL,'0' ;Is it a leading zero?
JNZ STORE_IT ;If no, store it.
MOV AL,32 ;Else, store a space.
STORE_IT: STOSW
MOV AL,CH ;Store delimiter character also.
STOSB
RET
;-------------------------------------------------;
; Approximate 700 filename buffer at end of code. ;
;-------------------------------------------------;
CURRENT_DIR DB 0
PURGE_DIR EQU CURRENT_DIR+68
FILE_NAME EQU PURGE_DIR+66
BUFFER EQU FILE_NAME+13
CODE ENDS
END START